iT邦幫忙

2024 iThome 鐵人賽

DAY 9
3
Python

Django 忍法帖——Django Ninja 入門指南系列 第 9

卷 9:請求(一)Django Ninja 處理請求概論(兼論 FBVs)

  • 分享至 

  • xImage
  •  

歡迎來到第三章第二節!

作為 API 的核心邏輯實現,view 函式無疑是 Django Ninja API 的靈魂所在。

Django Ninja 和 FastAPI、Flask 一樣,都是以 Function-Based Views(以下簡稱 FBVs)為主。所以它的學習重點,幾乎都繞圍在 view 函式的 input 和 output。

換句話說,整個 Django Ninja 框架的能力,構成了 view 函式的這些關鍵部分,包括但不限於:

  1. 處理 HTTP 請求的參數與 body。
  2. 處理 HTTP 回應內容的序列化與格式化。
  3. 資料驗證與錯誤處理。

它們共同構成了 Django Ninja 的主要功能。

本節和下一節,將集中討論上述 3 點中的前兩點——請求與回應。至於第三點,將留到第五章再行介紹。


本節導覽

繼上一節的「路由」後,本節將探討 Django Ninja 如何處理 HTTP 請求——如何解析 path、URL 查詢參數和 body。

本節一共有 4 篇:

  • 卷 9:請求(一)Django Ninja 處理請求概論(兼論 FBVs)
  • 卷 10:請求(二)Path Parameters
  • 卷 11:請求(三)Query Parameters
  • 卷 12:請求(四)Request Body 與 Schema 介紹

此外,因為 view 函式處理請求功能,已涉及 Django Ninja 如何使用 type hints 來驗證請求資料。我們的範例程式碼會開始加上 Python 型別提示

Type hints 的語法以 Python 3.12 為準。

官方文件

本系列的寫作不時會參考「Django Ninja 官方文件」,尤其是架構的呈現。

但文件畢竟是給全體開發者看的,並沒有充分考慮到學習的順序。

而本列系主要面向入門者,所以我們會更加注重實際操作與入門者的需求,並適時補充一些背景知識,確保學習曲線能相對平緩

此外,就框架本身,我們也會提供更多實例和解釋,讓新概念更好理解和掌握。

但無論如何,官方文件仍是你在使用 Django Ninja 時,需要時時參考的內容——雖然它寫得比 Django 或 Django REST framework 的文件,相對「簡單」很多!


本文主旨

本文作為第二節的概論,目標是讓你對 Django Ninja 的 view 函式與它如何處理 HTTP 請求有基本的認識

我們將透過以下三個重點來讓你逐步熟悉:

  1. FBVs 的優點。
  2. Django Ninja 對 HTTP 請求的處理流程。
  3. Django Ninja 與 Type Hints 的緊密結合。

話不說多,我們直接開始。


Class-based views (CBVs) 和 FBVs 都是實現 Django MTV 架構 中的 Views 手段,各有其適用場景。

CBVs 有重用程式碼優勢,適合大型專案。而 FBVs 則以簡單、直接為賣點,方便快速開發中小型專案。

兩者的比較,可參考這篇〈Day27 : CBV vs. FBV〉。

因為 Django Ninja 採 FBVs,本文只探討 FBVs 的優點。

一、FBV 的優點

FBVs 是 Django Ninja 採用的 view 形式。與 CBVs 相比,FBVs 更加簡潔、靈活,能夠讓開發者輕鬆編寫出 API 邏輯而不需要了解太多背景知識,比如「如何正確覆寫某個 CBV 屬性」。

簡潔與靈活

FBVs 不需要繼承或覆寫類別方法,所有的邏輯都集中在一個函式中。

這使得寫作和維護程式碼更加直觀。

由於 FBVs 本質是個函式,它可以更靈活地應用各種邏輯和條件,開發者能在單一函式中完全控制整個請求的處理流程,而不需要考慮類別的結構或繼承關係

容易 Debug

FBVs 的程式碼相對直觀,對於初學者來說,閱讀、理解起來更加容易。發生錯誤時,你可以快速定位問題,這是 CBVs 不易達到的便利性。

我的看法

Django 是個功能全面的框架,但也常被批評為「笨重」。FBVs 在一定程度上緩解了這種笨重感

試想,一個剛接觸 Django 的新手,在理解完各種框架的環境設定後,還要深入 CBVs 的世界,是否太過沉重?

總之,如果你問我,我絕對更偏好 FBVs——而且「輕量化」是現代開發的趨勢。


二、Django Ninja 對 HTTP 請求的處理流程

Django Ninja 對「請求」的處理可以分為幾個關鍵步驟:

  1. 路由配對:當請求進來時,框架首先會將來源 URL 與定義的路徑規則(端點)進行配對。若配對成功,則將 HTTP 請求與相關參數傳遞給 view 函式。
  2. 參數解析:從 URL 中提取路徑參數path parameters)和查詢參數query parameters),將它們轉換為 view 函式的「引數」(arguments)。根據函式的 type hints 自動進行型別轉換和驗證。
  3. Request body 處理:對於 POST 或 PUT 等帶有 body 的請求,Django Ninja 讓開發者使用 Schema(Pydantic BaseModel)定義 body 資料模型,並自動將傳入的資料對應到這些模型。

上述第 1 點已在本章第一節詳細解說。

第 2 和第 3 點則是本節共 4 篇文章的主要內容。


三、Django Ninja 與 Type Hints 的緊密結合

Django Ninja 非常依賴 Python 的 type hints 來處理 HTTP 請求中的資料。

並透過 Pydantic 實現了自動資料驗證類別轉換,減少了開發者手動檢查和轉換資料的負擔。

例如以下程式碼:

@router.get("/posts/{post_id}")
def get_post(request, post_id: int):
    return {"post_id": post_id}

post_id參數被標記為int時,Django Ninja 會進行型別檢查。如果傳入的參數無法轉換為int,框架會直接返回狀態碼為 422 的 HTTP 回應。

換言之,如果你將post_id標記為str,則 Django Ninja 會自動將post_id轉換為字串。

還記得剛開始接觸 Django Ninja時,我非常驚嘆竟然可以充分運用 Python type hints 到這般程度,讓它不僅僅是為了型別安全而服務,而是融入到整個 API 開發流程中

View 函式中的 request 參數

上面的例子中,有個值得注意的細節,就是 view 函式的第一參數——request

在 Django 中,view 函式的第一個參數必定為 request。這個參數名稱可以自行定義,但通常會命名為request

收到 HTTP 請求時,Django 會將整個請求打包成一個HttpRequest物件,並將它作為第一個參數傳給 view 函式,所以它必不可少

延伸閱讀:Django HttpRequest 常用屬性介紹

request參數在 Django 和 Django REST framework 中非常重要,因為它常用來取得請求的查詢參數、body 等內容。

在 Django Ninja 中,這些資料會直接透過函式參數來取得,因此request雖然仍不可少,但使用頻率較低


下一步

接下來,我們將深入探討 Django Ninja 處理請求的具體細節

下一篇將聚焦於路徑參數path parameters),並探討如何與 Django 原生的 path converters 搭配使用。敬請期待!

本文同步發表於我的部落格——Code and Me


上一篇
卷 8:路由(下)Django Ninja 路由設定
下一篇
卷 10:請求(二)路徑參數(Path Parameters)
系列文
Django 忍法帖——Django Ninja 入門指南14
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
gbaian10
iT邦新手 5 級 ‧ 2024-09-21 18:48:22

目前好像還沒說明 view function 中的 request 參數是做什的? 還是這是伏筆後面會講

是否每個 view function 一定要有這個 request? (以 FastAPI 來說是非必要,有需要用上才填即可)
如果一定要有的話是否一定要填在第一個參數? 另外沒有提供它的 Type Hints,mypy 應該會該該叫吧🤣

Kyo Huang iT邦新手 5 級 ‧ 2024-09-21 22:42:53 檢舉

哈哈哈,你看得很細耶!佩服佩服

本來打了一串要回你,但仔細想想,確實應該要直接補充在文章中。我自己習以為常,但讀者——尤其是沒用過 Django 的人,應該會和你有同樣的困惑,這無疑是我的疏忽

看來看去,還是補充在本篇最適合(因為是請求總論)

我剛剛已經新增了「View 函式中的 request 參數」在倒數第二段

request 的 type hints 我沒有加上去,因為怕程式碼資訊過多,後續的程式碼都會補上

gbaian10 iT邦新手 5 級 ‧ 2024-09-21 23:12:22 檢舉

其實 return type 也還沒寫
return type 在 fastapi 也可以是有意義的,它能夠幫你打包成對應的樣子並驗證回傳是否符合預期(或者將 schema 顯示在 api docs 上),不確定 Ninja 有沒有相似功能,等待後續介紹 😆

我看了你補充的內文了,request 確實不常用,但卻每個都要填,確實偶爾也會覺得挺煩的。
這種框架必填參數但該 func 又沒用到,我會把它命名為 _ ~~不然又換我的 ruff ARG001 又要該該叫 ~~,有用上就會命名成 request

這種時候命名底線還有個好處就是有時候就剛好多那幾個字母 linter 就要換行,有時候換行超醜的

Kyo Huang iT邦新手 5 級 ‧ 2024-09-22 13:27:14 檢舉

不確定 Ninja 有沒有相似功能,等待後續介紹 😆

有的,畢竟 Django Ninja 是「抄」FastAPI 的嘛!哈哈哈

在 Django Ninja 的原始碼中,有一個 TODO 是考慮讓 request 參數變成可選(類似 FastAPI),但這畢竟和 Django 的預設不同,我猜大概短期內都不會實作

這種框架必填參數但該 func 又沒用到,我會把它命名為 _ ~~不然又換我的 ruff ARG001 又要該該叫 ~~,有用上就會命名成 request

這倒是一個不錯的辦法,很能夠體現作為開發者的細心唷!

我要留言

立即登入留言